#include "BoxCollider.h"

using namespace SolidityEngine;

BoxCollider::BoxCollider(const Rect& bounds,const Vector2D& offset):
    Collider(),
    _bounds(bounds),
    _offset(offset)
{
    //ctor
}

BoxCollider::~BoxCollider()
{
    //dtor
}

Vector2D BoxCollider::_GetCenter() const
{
    Vector2D centre=_offset;
    Transform2D* transform=_gameobject->GetComponent<Transform2D>();
    if(transform){
        centre=centre+transform->Position();
    }
    return centre;
};

Rect BoxCollider::_GetBounds() const
{
    return _bounds;
};

Collision_ptr BoxCollider::_Test(Collider* collider)
{
    //test the type of the collider
    CircleCollider* ccoll = dynamic_cast<CircleCollider*>(collider);

    if(ccoll){
            //transform box to be in 'world' coordinates
            Rect current=_bounds;
            current.X()+=_GetCenter().X();
            current.Y()+=_GetCenter().Y();

            //get the point list of the box
            Vector2D* points = current.GetPoints();

            float minimum=10000000.0;
            //for each side of the box
            for(int i=0;i<4;i++)
            {
                int j;
                (i==3) ? j=0:j=i+1;
                //get the nearest point for the side
                Vector2D np = Vector2D::NearestPoint(points[i],points[j],ccoll->GetCenter());
                //
                float dist=Vector2D::Distance(np,ccoll->GetCenter());

                if (dist<minimum)
                {
                    minimum=dist;
                }
            }

            if(minimum<ccoll->Radius())
            {
                 return Collision_ptr(new Collision(collider->GetGameObject()));
            }
    }
    else{
        BoxCollider* bcoll = dynamic_cast<BoxCollider*>(collider);
        if(bcoll){
            //test if any point on the colliding object falls within the collision box of the current

            //transform both boxes to be in 'world' coordinates
            Rect current=_bounds;
            current.X()+=_GetCenter().X();
            current.Y()+=_GetCenter().Y();

            Rect collided=bcoll->Bounds();
            collided.X()+=bcoll->GetCenter().X();
            collided.Y()+=bcoll->GetCenter().Y();

            //get point lists for both boxes
            Vector2D* current_ps = current.GetPoints();
            Vector2D* collided_ps = current.GetPoints();

            //test each box for point containment
            for(int i=0; i<4 ; i++){
                if(current.Contains(collided_ps[i]) || collided.Contains(current_ps[i])){
                     return Collision_ptr(new Collision(collider->GetGameObject()));
                }
            }
        }
    }

    return Collision_ptr();
};

BoxCollider* BoxCollider::_Clone(){
    return new BoxCollider(*this);
};
